const protobuf = require('protobufjs')
//const got = require('got')
//const { misc2dic } = require('./registerJson/index')
//const { ksHttpHeaders } = require('./roomInfo')
//消息解码
const protobufJson = require('./protobuf/k.json')
const pbRoot = protobuf.Root.fromJSON(protobufJson)
const { giftMap } = require('./ksGift') //礼物映射表

const KsWsClient = require('ws');

//工具处理函数
const tools = require('../utils/tool')

//队列服务
const { getPAQueue } = require('../nodeQueue/queue.js')
var paQueue = null;
function rand(m, n) {
	return Math.ceil(Math.random() * (n - m + 1) + m - 1)
}

const ksConfig = {
	pageId: '',
	entryMain: null, //{ksUrl dyUrl wsServer roomId key soure buildStrJSON sendMsg closeSocket consoleLog setGlobalData getGlobalData getClientPool}
	wssAddress: '',
	token: '',
	liveStreamId: '',
	cookie: '',
	cookieObj: {},
}
class KuaishouClient {
	//构造函数
	constructor() {
		paQueue = getPAQueue() //初始化队列
	}
	//设置参数
	setConfig(config) {
		if(!config) return this
		Object.assign(ksConfig, config)
		if(!ksConfig.pageId) ksConfig.pageId = this.getPageId();
		return this
	}

	//启动
	start() {
		if(!ksConfig.wssAddress){
			ksConfig.entryMain.sendMsg(ksConfig.entryMain.buildStrJSON(401, `[ks-${this.entryMain.roomId}]>>>未获取到wssAddress`, '', 'ks'), ksConfig.entryMain.wsServer.clientId);
			return ksConfig.entryMain.consoleLog(`[ks-${ksConfig.entryMain.roomId}]>>>未获取到wssAddress`)
		}
		this.wsClient = new KsWsClient(ksConfig.wssAddress);
		this.wsClient.on('open', () => {
			ksConfig.entryMain.setGlobalData('serverConnected', true, ksConfig.entryMain.wsServer.clientId);
			ksConfig.entryMain.setGlobalData('connected', true, ksConfig.entryMain.wsServer.clientId);
			this.wsClient.send(this.getEnterRoomParams())
			//心跳包定时器
            this.ping();
		})
		this.wsClient.on('close', () => {
			this.stop();
		})
		this.wsClient.on('message', (e) => {
			//服务断开时，关闭
			if(!ksConfig.entryMain.getGlobalData('serverConnected', ksConfig.entryMain.wsServer.clientId)){
				return this.stop();
			}
			const msg = this.parseMessage(e) //解包消息
			if(msg && ksConfig?.entryMain?.wsServer){
				if(msg.type == 340 && msg?.data?.watchingUser?.length){ //观看用户消息列表
					paQueue.addTask(() => { //异步执行
						const watchingUser = [];
						msg.data.watchingUser.map(item => {
							if(!tools.verifyWord(item?.user?.userName || '')) return;
							watchingUser.push({
								uid: item?.user?.principalId || '', //用户ID
								nickName: item?.user?.userName || '', //昵称
								avatar: item?.user?.headUrl || '', //头像URL（如果有）
								sex: 0, //性别 1: 男, 2: 女, 0: 未设置
            					phone: '', //电话号码（如果有）
								ksCoin: item?.displayKsCoin || '', //快币数量（如果有）
								isTuhao: item?.tuhao || false, //是否是土豪标记（是=true,否=false）
							})
						})
						watchingUser.length > 0 && ksConfig.entryMain.sendMsg(ksConfig.entryMain.buildStrJSON(200, 'success', watchingUser, 'ks', 'RoomUserMessage'), ksConfig.entryMain.wsServer.clientId);
					});
				}
				if(msg.type == 310){ //聊天内容、礼物、点赞、分享消息列表
					//房间消息  （观看总数，点赞总数）
					paQueue.addTask(() => { //异步执行
						ksConfig.entryMain.sendMsg(ksConfig.entryMain.buildStrJSON(200, 'success', [{
							watchCount: msg?.data?.displayWatchingCount || 0, //累计观看总数
							currentCount: msg?.data?.pendingDuration || 0, //当前观看人数
							likeCount: msg?.data?.displayLikeCount || 0, //点赞总数
						}], 'ks', 'RoomInfoMessage'), ksConfig.entryMain.wsServer.clientId);
					});

					//评论聊天消息
					if(msg?.data?.commentFeeds && msg.data.commentFeeds.length){
						paQueue.addTask(() => { //异步执行
							const commentFeeds = [];
							msg.data.commentFeeds.map(item => {
								if(!tools.verifyWord(item?.user?.userName || '')) return;
								if(!tools.verifyWord(item?.content || '')) return;
								commentFeeds.push({
									uid: item?.user?.principalId || '', //用户ID
									nickName: item?.user?.userName || '', //昵称
									avatar: '', //头像URL（如果有）
									sex: 0, //性别 1: 男, 2: 女, 0: 未设置
            						phone: '', //电话号码（如果有）
									content: item?.content || '', //评论内容
								})
							})
							commentFeeds.length > 0 && ksConfig.entryMain.sendMsg(ksConfig.entryMain.buildStrJSON(200, 'success', commentFeeds, 'ks', 'ChatMessage'), ksConfig.entryMain.wsServer.clientId); 
						});
					}
					//点赞消息
					if(msg?.data?.likeFeeds && msg.data.likeFeeds.length){
						paQueue.addTask(() => { //异步执行
							const likeFeeds = [];
							msg.data.likeFeeds.map(item => {
								if(!tools.verifyWord(item?.user?.userName || '')) return;
								likeFeeds.push({
									uid: item?.user?.principalId || '', //用户ID
									nickName: item?.user?.userName || '', //昵称
									avatar: '', //头像URL（如果有）
									sex: 0, //性别 1: 男, 2: 女, 0: 未设置
            						phone: '', //电话号码（如果有）
								})
							})
							likeFeeds.length > 0 && ksConfig.entryMain.sendMsg(ksConfig.entryMain.buildStrJSON(200, 'success', likeFeeds, 'ks', 'LikeMessage'), ksConfig.entryMain.wsServer.clientId); 
						});
					}
					//礼物消息
					if(msg?.data?.giftFeeds && msg.data.giftFeeds.length){
						paQueue.addTask(() => { //异步执行
							const giftFeeds = [];
							msg.data.giftFeeds.map(item => {
								if(!tools.verifyWord(item?.user?.userName || '')) return;
								giftFeeds.push({
									uid: item?.user?.principalId || '', //用户ID
									nickName: item?.user?.userName || '', //昵称
									avatar: item?.user?.headUrl || '', //头像URL（如果有）
									giftId: item?.giftId, //礼物ID
									giftName: giftMap[item?.giftId] || '', //礼物名称
									giftCount: item?.comboCount || 0, //礼物总数量
								})
							})
							giftFeeds.length > 0 && ksConfig.entryMain.sendMsg(ksConfig.entryMain.buildStrJSON(200, 'success', giftFeeds, 'ks', 'GiftMessage'), ksConfig.entryMain.wsServer.clientId); 
						});
					}
				}
			}
		})
		this.wsClient.on('error', (e) => {
            ksConfig.entryMain.sendMsg(ksConfig.entryMain.buildStrJSON(401, `[ks-${ksConfig.entryMain.roomId}]>>>连接到快手wss失败：${e}`, '', 'ks'), ksConfig.entryMain.wsServer.clientId);
            this.stop() //停止
        })
	}

	//停止
	stop(){
		this.timer && clearTimeout(this.timer)
		this.wsClient && this.wsClient.close()
		this.wsClient = null;
		ksConfig.entryMain.setGlobalData('client', null, ksConfig.entryMain.wsServer.clientId);
		ksConfig.entryMain.setGlobalData('connected', false, ksConfig.entryMain.wsServer.clientId);
	}

	//发送心跳包
    ping() {
        this.wsClient && this.wsClient.send(this.getHeartbeatParams())
        this.timer = setTimeout(() => {
            this.wsClient && this.ping()
        }, 20 * 1000)
    }

	//获取 心跳参数
	getHeartbeatParams() {
		const params = {
			timestamp: new Date().getTime()
		}
		const heartbeatBuf = this.typeEncode('CSWebHeartbeat', params)
		const SocketMessage = this.typeEncode('SocketMessage', {
			payloadType: 1,
			payload: heartbeatBuf
		})
		return SocketMessage
	}

	//进入房间参数获取
	getEnterRoomParams() {
		const { liveStreamId, token, pageId } = ksConfig
		const params = this.enterRoom({token, liveStreamId, pageId})
		return params
	}

	//解析 消息体
	parseMessage(data) {
		const msg = this.decodeMessage(data)
		return msg
	}
	decodeMessage(msg) {
		const { payloadType, payload } = this.typeDecode('SocketMessage', msg)
		switch (payloadType) {
			case 310: //直播间弹幕信息 消息列表推送（聊天、点赞、礼物）
				return {type: 310, data: this.typeDecode('SCWebFeedPush', payload)}
			case 340: //统计数据推送（观看人数）
				return {type: 340, data: this.typeDecode('SCWebLiveWatchingUsers', payload)}
			default:
				return ''
			/*
			case 200:
				return this.typeDecode('CSWebEnterRoom', payload)
			case 1:
				return this.typeDecode('CSWebHeartbeat', payload)
			case 202:
				return this.typeDecode('CSWebUserExit', payload)
			case 101:
				return this.typeDecode('SCWebHeartbeatAck', payload)
			case 103:
				return this.typeDecode('SCWebError', payload)
			case 105:
				return this.typeDecode('SCInfo', payload)
			case 300:
				return this.typeDecode('SCWebEnterRoomAck', payload)
			case 310:
				return this.typeDecode('SCWebFeedPush', payload)
			case 330:
				return this.typeDecode('SCWebCurrentRedPackFeed', payload)
			case 340:
				return this.typeDecode('SCWebLiveWatchingUsers', payload)
			case 370:
				return this.typeDecode('SCWebGuessOpened', payload)
			case 371:
				return this.typeDecode('SCWebGuessClosed', payload)
			case 412:
				return this.typeDecode('SCWebRideChanged', payload)
			case 441:
				return this.typeDecode('SCWebBetChanged', payload)
			case 442:
				return this.typeDecode('SCWebBetClosed', payload)
			case 645:
				return this.typeDecode('SCWebLiveSpecialAccountConfigState', payload)
			case 758:
				return this.typeDecode('SCLiveWarningMaskStatusChangedAudience', payload)
			default:
				return ''
			*/
		}
	}
	enterRoom(params) {
		const CSWebEnterRoom = this.typeEncode('CSWebEnterRoom', params)
		const SocketMessage = this.typeEncode('SocketMessage', {
			payloadType: 200,
			payload: CSWebEnterRoom
		})
		return SocketMessage
	}
	typeEncode(type, payload) {
		const msgType = pbRoot.lookupType(`kuaishou.${type}`)
		const payloadCreate = msgType.create(payload)
		const msg = msgType.encode(payloadCreate).finish()
		return msg
	}
	typeDecode(type, payload) {
		const msgType = pbRoot.lookupType(`kuaishou.${type}`)
		const msg = msgType.decode(payload)
		if (type === 'SocketMessage') {
			return msg
		}
		var object = msgType.toObject(msg, {
			longs: String,
			enums: String,
			bytes: String
		})
		return object
	}
	getPageId() {
		let pageId = ''
		const charset = 'bjectSymhasOwnProp-0123456789ABCDEFGHIJKLMNQRTUVWXYZ_dfgiklquvxz'
		for (let i = 0; i < 16; i++) {
			pageId += charset[rand(0, 63)]
		}
		return (pageId += `_${new Date().getTime()}`)
	}

	//post请求
	async testPostRequest(){
		// return await got.post('https://live.kuaishou.com/live_graphql', {
		// 	headers: {
		// 		//Cookie: cookie,
		// 		//...ksHttpHeaders
		// 	},
		// 	json: {
		// 		//operationName: 'WebSocketInfoQuery',
		// 		//variables: { liveStreamId: liveStreamId },
		// 		//query: 'query WebSocketInfoQuery($liveStreamId: String) {\n  webSocketInfo(liveStreamId: $liveStreamId) {\n    token\n    webSocketUrls\n    __typename\n  }\n}\n'
		// 	}
		// }).json();
	}

	//get请求
	async testGetRequest(){
		// const res = await got.get(this.baseUrl + this.roomId, {
		// 	headers: ksHttpHeaders
		// })
		// const setCookies = res.headers['set-cookie']
	}
}
module.exports = KuaishouClient